/*
@STI LICENSE
(C) 2006-2008 Universit�t Innsbruck.

This file is part of myOntology.

myOntologyis free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

myOntologyis distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with myOntology.  If not, see <http://www.gnu.org/licenses/>.

@STI LICENSE */
package view.servlets;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Vocabulary;

import org.apache.commons.lang.StringEscapeUtils;
import org.myontology.users.Login;
import org.openrdf.model.URI;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.repository.RepositoryConnection;

import controller.HelperFunctions;
import controller.elementMapper.FreezepointMapper;
import controller.sesameDataConnector.AbstractDataConnector;

/**
 * Servlet implementation class for Servlet: AddFreezepoint
 *
 */
 public class AddFreezepoint extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
   static final long serialVersionUID = 1L;
   
    /* (non-Java-doc)
	 * @see javax.servlet.http.HttpServlet#HttpServlet()
	 */
	public AddFreezepoint() {
		super();
	}   	 	
	
	/* (non-Java-doc)
	 * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


		
		if ( !Login.LOGGED_IN.getValue(request) ) {
			response.sendRedirect( request.getRequestURI() + "login");
		}				
		
		response.setContentType("text/xml;charset=utf-8");
		response.setHeader("Cache-Control", "no-cache");
		response.setCharacterEncoding("UTF-8");
		
		
		String ret = "";
		ret += "<freezepointdiv>";
		
		
		String id = request.getParameter("id");
		URI uri = AbstractDataConnector.getURI( id );
		String description = request.getParameter("description");

		boolean freeze = true;
		try {
			org.openrdf.model.URI useruri = controller.sesameDataConnector.UserConnector.is_loged_on(request.getSession().getId());
			String owlexportContent = null;
			if( useruri==null ) {
				
				ret += "<![CDATA[Only logged in users can add new Freezepoints! <a href=\"login\" >Login now</a>.]]>";
				freeze = false;
			}
			else if( description==null || description.trim().equals("") ) {
				
				ret += "<![CDATA[The description must not be empty!]]>";
				freeze = false;
			}
			else {
				
				ExportOntology on = new ExportOntology();
				
				// generate last OWL-Export:
				owlexportContent = on.export( request.getContextPath(), uri );

				InputStream lastStream = getLastFreezepointStream( uri );
				if( owlexportContent!=null && lastStream!=null ) { // is there an previous freezepoint for this uri?
										
					// is the last freezepoint different from acutal OWL-export?
					if( contentsEqual( lastStream, new ByteArrayInputStream(owlexportContent.getBytes()), true ) ) {
						
						ret += "<![CDATA[The most actual freezepoint is still actual (find it at the <a href=\"" + HelperFunctions.getUriForHref(uri) + "/Frozen\" >overview</a>)]]>";
						freeze = false;
					}
				}				
			}	
			

			if( freeze==true && freeze( new ByteArrayInputStream(owlexportContent.getBytes()), uri, useruri, description ) ) {
				

				ret += "<![CDATA[Successfully created. (find it at the <a href=\"showAllFreezepoints.do?id="+HelperFunctions.getUriForHref(uri)+"\" >overview</a>) !]]>";
			}
		}
		catch( Exception e ) {
			ret += "<![CDATA[An unknown error occured:<br />";
			ret += StringEscapeUtils.escapeHtml( e.toString() );
			ret += " !]]>";
		}
		

		ret += "</freezepointdiv>";		
		
	    PrintWriter out = response.getWriter();
		
	    out.println("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>");
	    
	    out.println( ret );
	}
	
	private boolean freeze( InputStream stream, URI ontologyUri, URI userUri, String description ) throws Exception {
		
		boolean ret = false; 
		 
		// Store file 
		String filename = null; // a new filename should be generated.
		String outputPath = "";
		File f = null;
		int i = 0;
		do {
			UUID u = UUID.randomUUID();
			
			filename = u.toString();
			
			outputPath = this.getServletContext().getInitParameter( "FreezePointsDataDirectory" ) + File.separator + filename;
			
			f = new File( outputPath );
			
		} while( f.exists() && i++<10 );

		if( i<10 ) { // if not successfully found (should normally be found in first try
			

			RepositoryConnection con = AbstractDataConnector.getConnection();
			try {

				storeFile( stream, outputPath );
				
				// Insert Triples to Server
				Calendar now = GregorianCalendar.getInstance();
				URI freezUri = getNewFreezepointURI( ontologyUri, now );
								
				con.add( ontologyUri, Vocabulary.HASFREEZEPOINT, freezUri );
		
				con.add( freezUri, Vocabulary.HASUSERID, userUri );
				con.add( freezUri, Vocabulary.HASDATEANDTIME, new LiteralImpl( HelperFunctions.convertIntoString( now.getTimeInMillis() ) ) );
				con.add( freezUri, Vocabulary.DESCRIPTION, new LiteralImpl( description ) );
				con.add( freezUri, Vocabulary.FILENAME, new LiteralImpl( filename ) );
				
				con.commit();
				ret = true;
			}
			catch( Exception e ) {

				deleteFile( outputPath );
				con.rollback();
				
				throw e;
			}
		}
		
		return ret;
	}
	
	
	private URI getNewFreezepointURI( URI ontologyUri, Calendar now ) {

		String date = HelperFunctions.getFreezepointUriEnding( now );
		
		return new URIImpl( ontologyUri.stringValue() + "/Frozen/" + date );
	}
	
	private void deleteFile( String path ) {
		
		File f = new File( path );
		f.delete();
	}
	
	private boolean storeFile( InputStream inputstream, String outputPath ) throws Exception {
		
		// getNewOutputFilename
        File URLFile = new File(outputPath); 
        URLFile.createNewFile();
        
		//FileWriter fw = new FileWriter(URLFile); 
		FileOutputStream os = new FileOutputStream(URLFile, false);
		OutputStreamWriter fw = new OutputStreamWriter(os);
		BufferedWriter bw = new BufferedWriter(fw);
		
		InputStreamReader isr = new InputStreamReader( inputstream ); 
		BufferedReader br = new BufferedReader( isr ); 		
		String row = br.readLine(); 
		while (row != null) { 
			bw.write(row); 
			bw.newLine(); 
			row = br.readLine(); 
		} 
		
		bw.close();
		br.close();
		
		return true;
	}
	
	
	private InputStream getLastFreezepointStream( URI ontologyUri ) {

		InputStream ret = null;
		
		// determine with the repository the last Freezepoint of the ontology.

		try {
			URI freezepointUri = FreezepointMapper.selectLastFreecePoint(ontologyUri);			
			
			String filename = AbstractDataConnector.selectLiteralObject( freezepointUri, Vocabulary.FILENAME, null );
			
			String filepath = this.getServletContext().getInitParameter( "FreezePointsDataDirectory" ) + File.separator + filename;        
	
			File myfile = new File( filepath );
			
			if( myfile.canRead() ) {
	
				ret = new FileInputStream( myfile );
			}
		}
		catch( Exception e ) {
			
		}
		
		return ret;
	}
		
	/**
	* Returns <code>true</code> if both input streams byte contents is identical.
	* http://forum.java.sun.com/thread.jspa?threadID=564666&tstart=30
	* @param input1
	* first input to contents compare
	* @param input2
	* second input to contents compare
	* @return <code>true</code> if content is equal
	*/
	private boolean contentsEqual( InputStream is1, InputStream is2, boolean ignoreWhitespace ) {
		try {
			if( is1 == is2 )
				return true;
		
			if( is1 == null && is2 == null ) // no byte contents
				return true;
		
			if( is1 == null || is2 == null ) // only one has
				// contents
				return false;
		
			while( true )
			{
				int c1 = is1.read();
				while( ignoreWhitespace && isWhitespace( c1 ) )
					c1 = is1.read();
				
				int c2 = is2.read();
				
				while( ignoreWhitespace && isWhitespace( c2 ) )
					c2 = is2.read();
				
				if( c1 == -1 && c2 == -1 )
					return true;
				
				if( c1 != c2 )
					break;
		
			}
		}
		catch( IOException ex ) {
		}
		finally {
			try
			{
				try {
					if( is1 != null )
					{
						is1.close();
					}
				}
				finally {
					if( is2 != null )
					{
						is2.close();
					}
				}
			}
			catch( IOException e )
			{
				// Ignore
			}
		}
		return false;
	}

	private boolean isWhitespace( int c ) {
	if( c == -1 )
		return false;
	
	return Character.isWhitespace( ( char )c );
	}
}
